#include "video_protocol.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
#include <inttypes.h>
#include <math.h>
#include "../cJSON/cJSON.h"
#include "config.h"
#include "radar_protocol.h"
#include "log.h"
#include "fusion.h"
#include "polygon.h"
#include "platform_protocol.h"
#include "common.h"

typedef struct {
    union {
        int rect[4];
        struct {
            int x;
            int y;
            int width;
            int height;
        };
    };
    char guid[64];
} vehicle_info_t;

#define MAX_SCALE_COUNT 200

typedef struct {
    bool in_init_ok;
    bool out_init_ok;
    char guid[64];
    scale_t scale[MAX_SCALE_COUNT];
    int scale_count;
} scale_origin_t;

video_manager_t g_video_manager = {0};
scale_origin_t g_scale_origin = {0};

// 返回对应颜色的 ANSI 转义码
char *get_color_escape_code(int32_t code)
{
    switch (code) {
        case 1:
            return "\033[90m";  // 黑色
        case 2:
            return "\033[34m";  // 蓝色
        case 3:
            return "\033[33m";  // 棕色（这里用黄色近似）
        case 4:
            return "\033[32m";  // 绿色
        case 5:
            return "\033[37m";  // 灰色
        case 6:
            return "\033[97m";  // 白色（亮白）
        case 7:
            return "\033[31m";  // 红色
        case 8:
            return "\033[93m";  // 黄色（亮黄）
        case 9:
            return "\033[95m";  // 粉色（品红）
        case 10:
            return "\033[35m";  // 紫色
        case 11:
            return "\033[36m";  // 青色（青蓝）
        case 12:
            return "\033[90m";  // 深灰
        case 13:
            return "\033[93m";  // 金色（这里也用亮黄代替）
        default:
            return "\033[0m";   // 默认颜色
    }
}

char *get_car_color_by_code(int32_t code)
{
    switch (code) {
        case 1:
            return "黑色";    // black
        case 2:
            return "蓝色";    // blue
        case 3:
            return "棕色";    // brown
        case 4:
            return "绿色";    // green
        case 5:
            return "灰色";    // gray
        case 6:
            return "白色";    // white
        case 7:
            return "红色";    // red
        case 8:
            return "黄色";    // yellow
        case 9:
            return "粉色";    // pink
        case 10:
            return "紫色";    // purple
        case 11:
            return "青色";    // cyan
        case 12:
            return "深灰";    // dark gray
        case 13:
            return "金色";    // gold
        default:
            return "未识别";  // 未识别
    }
}

void print_struct_info(struct_info_t *struct_info)
{
    printf("<<<<<<<<<<<<<<<<<<<\n");
    printf("车牌号: %s\n", struct_info->plate_licence);
    printf("CarBrand: %s\n", struct_info->car_brand);
    printf("车辆颜色: %s%s\033[0m\n", get_color_escape_code(struct_info->car_color), get_car_color_by_code(struct_info->car_color));
    printf("Danger: %d\n", struct_info->danger);
    printf("号牌颜色: %d\n", struct_info->plate_color);
    printf("品牌型号: %d\n", struct_info->car_type);
    printf("CarTypeToll: %d\n", struct_info->car_type_toll);
    printf("Guid %s\n", struct_info->guid);
    printf(">>>>>>>>>>>>>>>>>>\n");
}

void write_struct_info_to_file(struct_info_t *struct_info, int8_t in_or_out)
{
    char str[1024] = {0};
    sprintf(str, "\n车型: %s\n车辆颜色: %d\nDanger: %d\n号牌颜色: %d\n车牌号: %s\n品牌型号: %d\nCarTypeToll: %d\n\n",
            struct_info->car_brand, struct_info->car_color, struct_info->danger, struct_info->plate_color,
            struct_info->plate_licence, struct_info->car_type, struct_info->car_type_toll);
    if (in_or_out == 1) {
        write_log("来向视频结构数据", struct_info->guid, str, NULL);
    }
    else {
        write_log("去向视频结构数据", struct_info->guid, str, NULL);
    }
    // print_struct_info(struct_info);
}

/**
 * 判断一个点是否在多边形内（射线法）
 *
 * @param x        测试点的 X 坐标
 * @param y        测试点的 Y 坐标
 * @param polygon  多边形顶点数组（按顺时针或逆时针顺序排列）
 * @param sizePoly 多边形的顶点个数
 * @return         如果点在多边形内，返回 true；否则返回 false
 */
static bool is_point_in_polygon(int x, int y, point_t *polygon, int sizePoly)
{
    bool inside = false;  // 标记点是否在多边形内，初始设为 false

    // 遍历多边形的每一条边（从点 i 到点 j），i 从 0 到 sizePoly - 1，j 是前一个点
    for (int i = 0, j = sizePoly - 1; i < sizePoly; j = i++) {
        // 判断点 (x, y) 是否在边 polygon[i] 到 polygon[j] 的 Y 值范围内（即穿过这条边）
        if ((polygon[i].y > y) != (polygon[j].y > y) &&
            // 再判断交点是否在点的左边，即射线从该点向右是否穿过边（用斜率公式算出交点的 x 坐标并比较）
            x < (polygon[j].x - polygon[i].x) * (y - polygon[i].y) /
                        (polygon[j].y - polygon[i].y) +
                    polygon[i].x) {
            // 每穿过一次边，就将 inside 状态取反（奇数次为 true，偶数次为 false）
            inside = !inside;
        }
    }

    return inside;
}

size_t vaild_coordinate_count(point_t *polygon, int sizePoly)
{
    size_t count = 0;
    for (int i = 0; i < sizePoly; i++) {
        if (polygon[i].x != 0 || polygon[i].y != 0) {
            count++;
        }
    }
    return count;
}

int get_lane_number(int x, int y, int8_t in_or_out)
{
    int size = 0;
    // 根据 in_or_out 选择对应的坐标数组
    if (in_or_out == 1) {
        for (int i = 0; i < g_config.lane_num; i++) {
            size = vaild_coordinate_count(g_config.in_lane_coordinate[i], sizeof(g_config.in_lane_coordinate[i]) / sizeof(g_config.in_lane_coordinate[i][0]));
            if (is_point_in_polygon(x, y, g_config.in_lane_coordinate[i], size)) {
                return i;
            }
        }
    }
    else {
        for (int i = 0; i < g_config.lane_num; i++) {
            size = vaild_coordinate_count(g_config.out_lane_coordinate[i], sizeof(g_config.out_lane_coordinate[i]) / sizeof(g_config.out_lane_coordinate[i][0]));
            if (is_point_in_polygon(x, y, g_config.out_lane_coordinate[i], size)) {
                return i;
            }
        }
    }
    return -1;
}

int get_col(int y, int16_t *y_list, int count)
{
    int col = -1;
    // printf("y: %d, y_list[0]: %d, y_list[count - 1]: %d\n", y, y_list[0], y_list[count - 1]);
    if (y < y_list[0] || y >= y_list[count - 1]) {
    }
    else {
        for (int i = 0; i < count - 1; i++) {
            if (y >= y_list[i] && y < y_list[i + 1]) {
                col = count - i - 1;
                break;
            }
        }
    }
    return col;
}

void video_protocol_init(void)
{
    g_video_manager.in_struct_info_queue = queue_init(MAX_VEHICLES, sizeof(struct_info_t));
    g_video_manager.in_video_frame_queue = queue_init(MAX_VIDEO_FRAME_COUNT, sizeof(video_frame_t));
    g_video_manager.out_struct_info_queue = queue_init(MAX_VEHICLES, sizeof(struct_info_t));
    g_video_manager.out_video_frame_queue = queue_init(MAX_VIDEO_FRAME_COUNT, sizeof(video_frame_t));
    if (!g_video_manager.in_struct_info_queue || !g_video_manager.in_video_frame_queue ||
        !g_video_manager.out_struct_info_queue || !g_video_manager.out_video_frame_queue) {
        printf("video_protocol_init failed\n");
        exit(1);
    }

    if (g_config.load_ruler_switch == 1) {
        int16_t vaild_count = 0;
        for (int i = 0; i < MAX_COLS; i++) {
            if (g_config.incoming_graduated_ruler[i] > 0) {
                vaild_count++;
            }
        }
        if (vaild_count == MAX_COLS) {
            memcpy(&g_video_manager.scale, &g_config.incoming_graduated_ruler, sizeof(g_video_manager.scale));
            g_scale_origin.in_init_ok = true;
        }

        for (int i = 0; i < MAX_COLS; i++) {
            if (g_config.outgoing_graduated_ruler[i] > 0) {
                vaild_count++;
            }
        }
        if (vaild_count == MAX_COLS) {
            memcpy(&g_video_manager.scale, &g_config.outgoing_graduated_ruler, sizeof(g_video_manager.scale));
            g_scale_origin.out_init_ok = true;
        }

        if (g_scale_origin.in_init_ok == false && g_scale_origin.out_init_ok == false) {
            uint8_t value = 0;
            update_config_file(CONFIG_FILE_PATH, "load_ruler_switch", &value, 0, 0);
        }
    }

    printf("g_scale_origin.in_init_ok: %d, g_scale_origin.out_init_ok: %d\n", g_scale_origin.in_init_ok, g_scale_origin.out_init_ok);
}

void video_protocol_deinit(void)
{
    queue_destroy(g_video_manager.in_struct_info_queue);
    queue_destroy(g_video_manager.in_video_frame_queue);
    queue_destroy(g_video_manager.out_struct_info_queue);
    queue_destroy(g_video_manager.out_video_frame_queue);
}

void clear_scale(scale_origin_t *scale)
{
    memset(scale, 0, sizeof(scale_origin_t));
}

void add_scale(scale_origin_t *scale, int16_t pixel_y, int64_t time)
{
    if (scale->scale_count >= MAX_SCALE_COUNT) {
        return;
    }

    scale->scale[scale->scale_count].pixel_y = pixel_y;
    scale->scale[scale->scale_count].time = time;
    scale->scale_count++;
}

void count_scale(scale_origin_t *scale, int16_t *pixel_y, bool in_or_out)
{
    if (scale->scale_count == 0) {
        return;
    }

    if (scale->scale_count < MAX_SCALE_COUNT) {
        generate_target_data_with_linear_interpolation(scale->scale_count, scale->scale, MAX_COLS, scale->scale);
    }
    for (int i = 0; i < MAX_COLS; i++) {
        pixel_y[i] = scale->scale[i].pixel_y;
    }
    scale->scale_count = 0;
    if (in_or_out == 1) {
        g_scale_origin.in_init_ok = true;
    }
    else {
        g_scale_origin.out_init_ok = true;
    }
}

// 将 UUID 的前三段拼接并转换为 uint64_t
uint64_t uuid_to_uint64(const char *uuid)
{
    // 检查字符串是否已经是纯数字
    int is_numeric = 1;
    for (const char *p = uuid; *p != '\0'; p++) {
        if (!isdigit(*p)) {
            is_numeric = 0;
            break;
        }
    }

    // 如果是纯数字，直接转换为 uint64_t
    if (is_numeric) {
        char *endptr;
        uint64_t result = strtoull(uuid, &endptr, 10);  // 10 表示十进制
        if (*endptr != '\0') {
            fprintf(stderr, "Invalid numeric format: %s\n", uuid);
            return -1;
        }
        return result;
    }

    // 否则，按 UUID 格式解析
    char buffer[32] = {0};  // 用于存储拼接后的字符串
    int segment_count = 0;
    const char *ptr = uuid;

    // 提取前 3 段
    while (*ptr && segment_count < 3) {
        if (*ptr == '-') {
            segment_count++;
        }
        else {
            // 将字符追加到 buffer
            size_t len = strlen(buffer);
            buffer[len] = *ptr;
            buffer[len + 1] = '\0';
        }
        ptr++;
    }

    // 将拼接后的字符串转换为 uint64_t
    char *endptr;
    uint64_t result = strtoull(buffer, &endptr, 16) & 0x7FFFFFFFFFFFFFFF;  // 16 表示十六进制
    if (*endptr != '\0') {
        fprintf(stderr, "Invalid UUID format: %s\n", uuid);
        return -1;
    }
    return result;
}

// 将 int64_t 转换为十进制字符串
void uint64_to_string(uint64_t value, char *buffer, size_t buffer_size)
{
    // 使用 snprintf 将 int64_t 转换为字符串
    int result = snprintf(buffer, buffer_size, "%llu", value);
    if (result < 0 || result >= buffer_size) {
        fprintf(stderr, "Buffer too small or conversion failed.\n");
        buffer[0] = '\0';  // 清空缓冲区
    }
}

void convert_guid(const char *guid, char *buffer, size_t buffer_size)
{
    uint64_t value = uuid_to_uint64(guid);
    uint64_to_string(value, buffer, buffer_size);
}

// 子函数：解析 Vehicles 数组
int parse_vehicles(cJSON *vehicles_array, vehicle_info_t *vehicles, int max_vehicles)
{
    int vehicle_count = 0;

    // 遍历 Vehicles 数组
    for (int i = 0; i < cJSON_GetArraySize(vehicles_array); i++) {
        if (vehicle_count >= max_vehicles) {
            break;  // 达到最大数量，停止解析
        }

        cJSON *vehicle = cJSON_GetArrayItem(vehicles_array, i);
        if (vehicle == NULL) {
            continue;
        }

        // 提取 GUID
        cJSON *guid = cJSON_GetObjectItemCaseSensitive(vehicle, "GUID");
        if (cJSON_IsString(guid) && (guid->valuestring != NULL)) {
            convert_guid(guid->valuestring, vehicles[vehicle_count].guid, sizeof(vehicles[vehicle_count].guid));
        }
        else {
            continue;  // GUID 无效，跳过
        }

        // 提取 Rect
        cJSON *detect = cJSON_GetObjectItemCaseSensitive(vehicle, "Detect");
        if (detect != NULL) {
            cJSON *body = cJSON_GetObjectItemCaseSensitive(detect, "Body");
            if (body != NULL) {
                cJSON *rect = cJSON_GetObjectItemCaseSensitive(body, "Rect");
                if (cJSON_IsArray(rect) && (cJSON_GetArraySize(rect) == 4)) {
                    for (int j = 0; j < 4; j++) {
                        cJSON *item = cJSON_GetArrayItem(rect, j);
                        if (cJSON_IsNumber(item)) {
                            vehicles[vehicle_count].rect[j] = item->valueint;
                        }
                    }
                    vehicle_count++;  // 解析成功，车辆数量加 1
                }
            }
        }
    }

    return vehicle_count;  // 返回解析的车辆数量
}

/**
 * @brief 解析视频检测上传的车辆信息（addDetectAll），并更新标尺或位图信息。
 * @param root 指向 cJSON 格式的根节点
 */
void parse_adddetectall(cJSON *root)
{
    int in_or_out = 0;  // 0: 未知，1: 上行（来向），2: 下行（去向）
    cJSON *device_code = NULL;

    // 获取"detail"字段
    cJSON *detail = cJSON_GetObjectItemCaseSensitive(root, "detail");
    int64_t current_time = 0, diff_time = 0;
    if (detail == NULL) {
        fprintf(stderr, "Missing 'detail' field!\n");
        return;
    }

    // 获取设备编号，判断是来向设备还是去向设备
    device_code = cJSON_GetObjectItemCaseSensitive(detail, "DeviceCode");
    if (device_code == NULL || !cJSON_IsString(device_code)) {
        fprintf(stderr, "Missing or invalid 'DeviceCode' field!\n");
        return;
    }

    // 判断设备方向（来向或去向）
    if (strcmp(device_code->valuestring, g_config.in_video_device_code) == 0) {
        in_or_out = 1;
    }
    else if (strcmp(device_code->valuestring, g_config.out_video_device_code) == 0) {
        in_or_out = 2;
    }
    else {
        return;  // 非来向或去向设备，跳过
    }

    // 获取车辆数组
    cJSON *vehicles_array = cJSON_GetObjectItemCaseSensitive(detail, "Vehicles");
    if (!cJSON_IsArray(vehicles_array)) {
        fprintf(stderr, "Missing or invalid 'Vehicles' field!\n");
        return;
    }

    // 解析车辆信息
    vehicle_info_t vehicles[MAX_VEHICLES] = {0};
    int vehicle_count = parse_vehicles(vehicles_array, vehicles, MAX_VEHICLES);

    // 准备处理过程中的变量
    int16_t pixel_y;                  // 车辆底部像素位置
    int16_t center_x;                 // 车辆中心点X坐标
    int8_t lane, col;
    video_frame_t video_frame = {0};  // 当前帧信息
    Bitmap bitmap = {0};              // 车道列位图
    char buf[2048] = {0};             // 调试日志缓冲
    int offset = 0;
    rect_t rect = {0};                // 未使用变量

    // 来向处理逻辑
    if (in_or_out == 1) {
        if (g_config.video_debug == 1 && vehicle_count > 0) {
            printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
        }

        for (int i = 0; i < vehicle_count; i++) {
            // 计算车辆中心点与底部坐标
            center_x = (int32_t)round(vehicles[i].x + vehicles[i].width * g_config.video_center_x_ratio);
            pixel_y = vehicles[i].y + vehicles[i].height;

            // 判断车道号
            lane = get_lane_number(center_x, pixel_y, 1);

            // 打印调试信息
            if (g_config.video_debug == 1 && lane != -1) {
                printf("\033[33mguid: %s, x: %d, y: %d, width: %d, height: %d, lane : %d\033[0m\n",
                       vehicles[i].guid, vehicles[i].x, vehicles[i].y,
                       vehicles[i].width, vehicles[i].height, lane);
            }

            // 累加调试文本
            offset += snprintf(buf + offset, sizeof(buf) - offset,
                               "guid: %s, x: %d, y: %d, width: %d, height: %d, lane: %d\n",
                               vehicles[i].guid, vehicles[i].x, vehicles[i].y,
                               vehicles[i].width, vehicles[i].height, lane);

            // 标尺计算逻辑（用于标定像素到真实距离）
            if (!g_scale_origin.in_init_ok) {
                if ((strlen(g_scale_origin.guid) == 0 || strcmp(g_scale_origin.guid, vehicles[i].guid) == 0) &&
                    pixel_y > g_config.scale_range[0] &&
                    pixel_y <= g_config.scale_range[1] &&
                    lane == g_config.reference_lane) {
                    clear_scale(&g_scale_origin);
                    strcpy(g_scale_origin.guid, vehicles[i].guid);
                    add_scale(&g_scale_origin, pixel_y, get_current_time_in_milliseconds());
                    // printf("开始标尺 guid: %s pixel_y: %d lane: %d\n", g_scale_origin.guid, pixel_y, lane);
                }
                else if (strcmp(g_scale_origin.guid, vehicles[i].guid) == 0) {
                    add_scale(&g_scale_origin, pixel_y, get_current_time_in_milliseconds());
                    // printf("添加标尺 count: %d pixel_y: %d lane: %d guid: %s\n",
                    //        g_scale_origin.scale_count, pixel_y, lane, g_scale_origin.guid);
                }

                // 判断是否达到终点，完成标尺计算
                if (strcmp(g_scale_origin.guid, vehicles[i].guid) == 0 &&
                    pixel_y >= g_config.scale_range[2]) {
                    count_scale(&g_scale_origin, g_video_manager.scale, 1);
                    if (g_config.load_ruler_switch == 0) {
                        // printf("更新标尺成功\n");
                        update_config_file(CONFIG_FILE_PATH, "incoming_graduated_ruler",
                                           g_video_manager.scale,
                                           sizeof(g_video_manager.scale) / sizeof(g_video_manager.scale[0]), 0);
                    }
                }

                // 判断标尺时间超时自动清除
                if (g_scale_origin.scale_count > 0) {
                    current_time = get_current_time_in_milliseconds();
                    diff_time = current_time - g_scale_origin.scale[g_scale_origin.scale_count - 1].time;
                    if (diff_time > 1000) {
                        clear_scale(&g_scale_origin);
                    }
                }
            }
            // 正常位图更新逻辑
            else {
                if (video_frame.obj_num > VIDEO_INFO_SIZE)
                    break;
                if (pixel_y <= g_config.scale_range[2] && pixel_y >= g_config.scale_range[0]) {
                    video_obj_info_t obj_info;
                    if (lane != -1) {
                        col = get_col(pixel_y, g_video_manager.scale, MAX_COLS);
                        if (col == -1)
                            continue;

                        set_bit(&bitmap, lane, col);
                        strcpy(obj_info.guid, vehicles[i].guid);
                        obj_info.row = lane;
                        obj_info.col = col;
                        memcpy(&video_frame.obj_info[video_frame.obj_num++], &obj_info, sizeof(video_obj_info_t));
                    }
                }
            }
        }

        // 写入队列
        video_frame.frame_time = get_current_time_in_milliseconds();
        memcpy(&video_frame.obj_map, &bitmap, sizeof(Bitmap));
        queue_enqueue(g_video_manager.in_video_frame_queue, &video_frame);

        if (g_config.video_debug == 1 && vehicle_count > 0) {
            printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n\n");
        }
    }

    // 去向处理逻辑（基本与来向一致，略作调整）
    else {
        if (g_config.video_debug == 1 && vehicle_count > 0) {
            printf("<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");
        }

        for (int i = 0; i < vehicle_count; i++) {
            center_x = (int32_t)round(vehicles[i].x + vehicles[i].width * g_config.video_center_x_ratio);
            pixel_y = vehicles[i].y + vehicles[i].height;
            lane = get_lane_number(center_x, pixel_y, 2);

            // if (g_config.video_debug == 1 && lane != -1) {
            if (g_config.video_debug == 1) {
                printf("\033[33mguid: %s,  y: %d, lane : %d\033[0m\n",
                       vehicles[i].guid, pixel_y, lane);
            }

            offset += snprintf(buf + offset, sizeof(buf) - offset,
                               "guid: %s, x: %d, y: %d, width: %d, height: %d, lane: %d\n",
                               vehicles[i].guid, vehicles[i].x, vehicles[i].y,
                               vehicles[i].width, vehicles[i].height, lane);

            // 去向标尺处理
            if (!g_scale_origin.out_init_ok) {
                if ((strlen(g_scale_origin.guid) == 0 || strcmp(g_scale_origin.guid, vehicles[i].guid) == 0) &&
                    pixel_y > g_config.scale_range[0] &&
                    pixel_y <= g_config.scale_range[1] &&
                    lane == g_config.reference_lane) {
                    clear_scale(&g_scale_origin);
                    strcpy(g_scale_origin.guid, vehicles[i].guid);
                    add_scale(&g_scale_origin, pixel_y, get_current_time_in_milliseconds());
                    printf("开始去向标尺 guid: %s pixel_y: %d lane: %d\n", g_scale_origin.guid, pixel_y, lane);
                }
                else if (strcmp(g_scale_origin.guid, vehicles[i].guid) == 0) {
                    add_scale(&g_scale_origin, pixel_y, get_current_time_in_milliseconds());
                    printf("添加去向标尺 count: %d pixel_y: %d lane: %d guid: %s\n",
                           g_scale_origin.scale_count, pixel_y, lane, g_scale_origin.guid);
                }

                // 去向标尺完成，标尺镜像保存
                if (strcmp(g_scale_origin.guid, vehicles[i].guid) == 0 &&
                    pixel_y <= g_config.scale_range[2]) {
                    count_scale(&g_scale_origin, g_video_manager.scale, 0);
                    if (g_config.load_ruler_switch == 0) {
                        printf("更新去向标尺成功\n");

                        // 镜像翻转scale数组
                        for (int i = 0; i < MAX_COLS / 2; i++) {
                            int tmp = g_video_manager.scale[i];
                            g_video_manager.scale[i] = g_video_manager.scale[MAX_COLS - i - 1];
                            g_video_manager.scale[MAX_COLS - i - 1] = tmp;
                        }

                        update_config_file(CONFIG_FILE_PATH, "outgoing_graduated_ruler",
                                           g_video_manager.scale,
                                           sizeof(g_video_manager.scale) / sizeof(g_video_manager.scale[0]), 0);
                    }
                }

                if (g_scale_origin.scale_count > 0) {
                    current_time = get_current_time_in_milliseconds();
                    diff_time = current_time - g_scale_origin.scale[g_scale_origin.scale_count - 1].time;
                    if (diff_time > 1000) {
                        // printf("超时清除标尺\n");
                        clear_scale(&g_scale_origin);
                    }
                }
            }

            else {
                if (video_frame.obj_num > VIDEO_INFO_SIZE)
                    break;
                if (pixel_y >= g_config.scale_range[2] && pixel_y < g_config.scale_range[0]) {
                    video_obj_info_t obj_info;
                    if (lane != -1) {
                        col = get_col(pixel_y, g_video_manager.scale, MAX_COLS);
                        if (col == -1)
                            continue;

                        set_bit(&bitmap, lane, col);
                        strcpy(obj_info.guid, vehicles[i].guid);
                        obj_info.row = lane;
                        obj_info.col = col;
                        memcpy(&video_frame.obj_info[video_frame.obj_num++], &obj_info, sizeof(video_obj_info_t));
                    }
                }
            }
        }

        // char time_str[64] = {0};
        // printf("视频去向位图: %s\n", get_current_time_string(time_str, sizeof(time_str)));
        // print_bitmap(&bitmap);

        // 写入队列
        video_frame.frame_time = get_current_time_in_milliseconds();
        memcpy(&video_frame.obj_map, &bitmap, sizeof(Bitmap));
        queue_enqueue(g_video_manager.out_video_frame_queue, &video_frame);

        if (g_config.video_debug == 1 && vehicle_count > 0) {
            printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n\n\n");
        }
    }
}

void parse_addstructall(cJSON *root)
{
    int in_or_out = 0;  // 0: 未知，1: 上行，2: 下行
    cJSON *device_code = NULL;
    cJSON *detail = cJSON_GetObjectItemCaseSensitive(root, "detail");
    struct_info_t struct_info = {0};
    if (detail == NULL) {
        fprintf(stderr, "Missing 'detail' field!\n");
        return;
    }

    // 检查 DeviceCode 字段
    device_code = cJSON_GetObjectItemCaseSensitive(detail, "DeviceCode");
    if (device_code == NULL || !cJSON_IsString(device_code)) {
        fprintf(stderr, "Missing or invalid 'DeviceCode' field!\n");
        return;
    }

    // 判断上行或下行
    if (strcmp(device_code->valuestring, g_config.in_video_device_code) == 0) {
        in_or_out = 1;
    }
    else if (strcmp(device_code->valuestring, g_config.out_video_device_code) == 0) {
        in_or_out = 2;
    }
    else {
        // printf("Unknown device code: %s\n", device_code->valuestring);
        return;  // 不是上行或下行设备，跳过
    }

    cJSON *vehicles_array = cJSON_GetObjectItemCaseSensitive(detail, "Vehicles");
    if (!cJSON_IsArray(vehicles_array)) {
        fprintf(stderr, "Missing or invalid 'Vehicles' field!\n");
        return;
    }
    if (cJSON_GetArraySize(vehicles_array) == 0) {
        return;
    }
    cJSON *vehicle = cJSON_GetArrayItem(vehicles_array, 0);
    if (vehicle == NULL) {
        return;
    }
    cJSON *guid = cJSON_GetObjectItemCaseSensitive(vehicle, "GUID");
    if (guid == NULL || !cJSON_IsString(guid)) {
        return;
    }
    strcpy(struct_info.guid, guid->valuestring);

    cJSON *recognize = cJSON_GetObjectItemCaseSensitive(vehicle, "Recognize");
    if (recognize == NULL) {
        return;
    }

#if 0
    cJSON *images = cJSON_GetObjectItemCaseSensitive(root, "imageDatas");
    cJSON *imageid = cJSON_GetObjectItemCaseSensitive(recognize, "ImageId");  // 获取结构化数据中的imageid
    if (images && imageid) {
        cJSON *imageids = cJSON_GetObjectItemCaseSensitive(images, imageid->valuestring);
        if (imageids) {
            send_image_to_platform(imageids->valuestring, guid->valuestring, in_or_out == 1 ? RADAR_INCOMING : RADAR_OUTGOING);
        }
    }
#endif

    cJSON *brand = cJSON_GetObjectItemCaseSensitive(recognize, "Brand");
    if (brand) {
        cJSON *top_list = cJSON_GetObjectItemCaseSensitive(brand, "TopList");
        if (top_list) {
            cJSON *top = cJSON_GetArrayItem(top_list, 0);
            if (top) {
                cJSON *name = cJSON_GetObjectItemCaseSensitive(top, "Name");
                if (name) {
                    if (cJSON_IsString(name)) {
                        strcpy(struct_info.car_brand, name->valuestring);
                    }
                }
            }
        }
    }
    else {
        // printf("Brand: NULL\n");
        // return;
    }

    cJSON *color = cJSON_GetObjectItemCaseSensitive(recognize, "Color");
    if (color) {
        cJSON *top_list = cJSON_GetObjectItemCaseSensitive(color, "TopList");
        if (top_list) {
            cJSON *top = cJSON_GetArrayItem(top_list, 0);
            if (top) {
                cJSON *code = cJSON_GetObjectItemCaseSensitive(top, "Code");
                if (code && cJSON_IsString(code)) {
                    struct_info.car_color = strtol(code->valuestring, NULL, 10);
                }
            }
        }
    }
    else {
        // printf("Color: NULL\n");
        // return;
    }

    cJSON *danger = cJSON_GetObjectItemCaseSensitive(recognize, "Danger");
    if (danger) {
        cJSON *top_list = cJSON_GetObjectItemCaseSensitive(danger, "TopList");
        if (top_list) {
            cJSON *top = cJSON_GetArrayItem(top_list, 0);
            if (top) {
                cJSON *code = cJSON_GetObjectItemCaseSensitive(top, "Code");
                if (code && cJSON_IsString(code)) {
                    struct_info.danger = strtol(code->valuestring, NULL, 10);
                }
            }
        }
    }
    else {
        // printf("Danger: NULL\n");
        // return;
    }

    cJSON *lid = cJSON_GetObjectItemCaseSensitive(recognize, "Lid");
    if (lid) {
        cJSON *top_list = cJSON_GetObjectItemCaseSensitive(lid, "TopList");
        if (top_list) {
            cJSON *top = cJSON_GetArrayItem(top_list, 0);
            if (top) {
                cJSON *code = cJSON_GetObjectItemCaseSensitive(top, "Code");
                if (code && cJSON_IsString(code)) {
                    struct_info.plate_color = strtol(code->valuestring, NULL, 10);
                }
            }
        }
    }
    else {
        // printf("PlateColor: NULL\n");
        return;
    }

    cJSON *plate = cJSON_GetObjectItemCaseSensitive(recognize, "Plate");
    if (plate) {
        cJSON *color = cJSON_GetObjectItemCaseSensitive(plate, "Color");
        if (color) {
            cJSON *code = cJSON_GetObjectItemCaseSensitive(color, "Code");
            if (code && cJSON_IsString(code)) {
                struct_info.plate_color = strtol(code->valuestring, NULL, 10);
            }
            else {
                printf("PlateColor: NULL\n");
            }
        }
        cJSON *licence = cJSON_GetObjectItemCaseSensitive(plate, "Licence");
        if (licence && cJSON_IsString(licence)) {
            strcpy(struct_info.plate_licence, licence->valuestring);
        }
        else {
            printf("PlateLicence: NULL\n");
        }
    }
    else {
        printf("Plate: NULL\n");
        return;
    }

    cJSON *type = cJSON_GetObjectItemCaseSensitive(recognize, "Type");
    if (type) {
        cJSON *top_list = cJSON_GetObjectItemCaseSensitive(type, "TopList");
        if (top_list) {
            cJSON *top = cJSON_GetArrayItem(top_list, 0);
            if (top) {
                cJSON *code = cJSON_GetObjectItemCaseSensitive(top, "Code");
                if (code && cJSON_IsString(code)) {
                    struct_info.car_type = strtol(code->valuestring, NULL, 10);
                }
                cJSON *type_toll = cJSON_GetObjectItemCaseSensitive(top, "TypeToll");
                if (type_toll && cJSON_IsString(type_toll)) {
                    struct_info.car_type_toll = strtol(type_toll->valuestring, NULL, 10);
                }
            }
        }
    }
    else {
        printf("CarType: NULL\n");
        // return;
    }
    if (in_or_out == 1) {
        queue_enqueue(g_video_manager.in_struct_info_queue, &struct_info);
        write_struct_info_to_file(&struct_info, 1);
        if (g_config.struct_debug == 1) {
            print_struct_info(&struct_info);
        }
    }
    else {
        queue_enqueue(g_video_manager.out_struct_info_queue, &struct_info);
        write_struct_info_to_file(&struct_info, 2);
        if (g_config.struct_debug == 1) {
            print_struct_info(&struct_info);
        }
    }
}

void parse_json(const char *json_str)
{
    uint8_t in_or_out = 0;  // 0: 未知，1: 上行，2: 下行
    cJSON *root = NULL;
    cJSON *cmd = NULL;

    // 解析 JSON 字符串
    root = cJSON_Parse(json_str);
    if (root == NULL) {
        fprintf(stderr, "Failed to parse JSON!\n");
        goto cleanup;
    }

    // 检查 cmd 字段是否为 "addDetectAll"
    cmd = cJSON_GetObjectItemCaseSensitive(root, "cmd");
    if (cmd == NULL || !cJSON_IsString(cmd)) {
        goto cleanup;
    }

    if (strcmp(cmd->valuestring, "addDetectAll") == 0) {
        // printf("detect len: %d\n", strlen(json_str));
        // printf("收到%d字节的检测数据\n", strlen(json_str));
        parse_adddetectall(root);
    }
    else if (strcmp(cmd->valuestring, "addStructAll") == 0) {
        // printf("struct len: %d\n", strlen(json_str));
        // printf("收到%d字节的结构数据\n", strlen(json_str));
        parse_addstructall(root);
    }

cleanup:
    // 释放 cJSON 对象
    if (root != NULL) {
        cJSON_Delete(root);
    }
}

struct_info_t *get_struct_info_by_guid(const char *guid, uint8_t dev_type)
{
    if (!guid) {
        return NULL;
    }
    Queue_t *struct_info_queue = (dev_type == RADAR_INCOMING) ? g_video_manager.in_struct_info_queue : g_video_manager.out_struct_info_queue;
    size_t struct_info_count = get_queue_count(struct_info_queue);
    for (int i = 0; i < struct_info_count; i++) {
        struct_info_t *struct_info = (struct_info_t *)queue_get_node(struct_info_queue, from_tail, i);
        if (struct_info && strcmp(struct_info->guid, guid) == 0) {
            return struct_info;
        }
    }
    return NULL;
}

struct_info_t *get_struct_info_by_radar_id(uint16_t id, uint8_t dev_type)
{
    return NULL;
}

bool video_detect_emergency_lane()
{
    video_frame_t *v_frame = queue_get_node(g_video_manager.in_video_frame_queue, from_tail, 0);
    if (v_frame == NULL) {
        return true;
    }
    for (int i = 0; i < v_frame->obj_num; i++) {
        if (v_frame->obj_info[i].row == g_config.lane_num - 1) {
            return true;
        }
    }
    return false;
}